package com.googlecode.vmock.utils;

/**
 * Represent a single element of a variable-length chain. Every element of a chain can hold a value of a given type.
 * 
 * @author marcin.jagus
 * @param <T> Type of hold value
 */
public class Chain<T> {

    /**
     * Value hold by this element of a chain.
     */
    private T value;

    /**
     * Previous element of a chain. <code>Null</code> if this is the first element in a chain.
     */
    private Chain<T> previous;

    /**
     * Next element of a chain. <code>Null</code> if this is the last element of a chain.
     */
    private Chain<T> next;

    /**
     * Creates a new chain that holds a given value
     * 
     * @param value Given value
     */
    public Chain(T value) {
        this.value = value;
    }

    /**
     * Returns a value hold by this chain.
     * 
     * @return value hold by this chain
     */
    public T getValue() {
        return value;
    }

    /**
     * Returns previous element of a chain.
     * 
     * @return previous element of a chain
     */
    public Chain<T> getPrevious() {
        return previous;
    }

    /**
     * Returns next element of a chain.
     * 
     * @return next element of a chain
     */
    public Chain<T> getNext() {
        return next;
    }

    /**
     * Creates a new element of a chain and adds it before this element.
     * 
     * @param value Value which will be held by new chain element
     * @return the new chain element
     */
    public Chain<T> addBefore(T value) {
        Chain<T> chain = new Chain<T>(value);
        chain.next = this;
        chain.previous = this.previous;

        if (this.previous != null) {
            this.previous.next = chain;
        }
        this.previous = chain;

        return chain;
    }

    /**
     * Creates a new element of a chain and adds it after this element.
     * 
     * @param value Value which will be held by new chain element
     * @return the new chain element
     */
    public Chain<T> addAfter(T value) {
        Chain<T> chain = new Chain<T>(value);
        chain.previous = this;
        chain.next = this.next;

        if (this.next != null) {
            this.next.previous = chain;
        }

        this.next = chain;

        return chain;
    }
}
